from utils.prettyrepr import prettify_class
from utils.namespace import Namespace
from utils.persist import ShelvePersistent

from datetime import datetime


@prettify_class
class Event(object):
    """An event is an entry in a task's log. Example events are task created, pomodoro started,
    external interruption, etc. Each event has an associated timestamp and an extra data dictionary
    that can store arbitrary data, e.g. the type of interruption.
    """
    def __init__(self, etype, time=None, **data):
        if time is None:
            time = datetime.now()
        self.type = etype
        self.time = time
        self.data = Namespace(data)

    def __info__(self):
        return "%s: %s - %s" % (self.time, self.type, self.data)

    def __call__(self, time=None, **data):
        """An event can be called to create another event with the same type and initial data. The
        new event will have a different time and may redefine the data defined by its creator."""
        event = type(self)(self.type, time)
        event.data.update(self.data)
        event.data.update(data)
        return event


Event.task_created = Event("task created")
Event.task_completed = Event("task completed")
Event.pomodoro_started = Event("pomodoro started")
Event.pomodoro_completed = Event("pomodoro completed")
Event.pomodoro_voided = Event("pomodoro voided")
Event.internal_interruption = Event("internal interruption")
Event.external_interruption = Event("external interruption")
Event.interruption_handled = Event("interruption handled")


@prettify_class
class Task(object):
    def __init__(self, name, completed=False, **data):
        self.name = name
        self.completed = completed
        self.data = Namespace(data)
        self.events = []
        self.parent = None
        self.children = []
        self.log(Event.task_created())

    def __info__(self):
        parent = "<N/A>" if self.parent is None else self.parent.name
        return ("%s, parent=%s, nchildren=%d" % (self.name, parent, len(self.children)))

    def tree_view(self, level=0):
        parts = ["    " * level, str(self)]
        parts.extend(child.tree_view(level+1) for child in self.children)
        return "".join(parts)

    def copy(self):
        """A task with the same name, parent, and children."""
        return type(self)(self.name, self.parent, self.children)

    def log(self, event):
        self.events.append(event)
        print self
        print "adding event"
        print event

    @property
    def fullname(self):
        names = [task.name for task in self.path_to_root()]
        names.reverse()
        return ".".join(names)

    def path_to_root(self):
        task = self
        while task is not None:
            yield task
            task = task.parent

    def add_child(self, child):
        if child.parent is not None:
            raise ValueError("argument task has a parent")
        self.children.append(child)
        child.parent = self

    def remove_child(self, child):
        if child.parent is not self:
            raise ValueError("argument task is not a child of self")
        self.children.remove(child)
        child.parent = None

    def set_parent(self, parent):
        if parent is not None:
            parent.add_child(self)

    def clear_parent(self):
        if self.parent is not None:
            self.parent.remove_child(self)
            self.parent = None


class Project(ShelvePersistent):
    def __init__(self):
        self.pending_tasks = []
        self.todo_today = []
        self.completed_tasks = []

    def add_task(self, *args, **kwargs):
        task = Task(*args, **kwargs)
        self.pending_tasks.append(task)
        return task


p = Project()
t = p.add_task("foo")
